In multithread computing environments, multiple threads of execution can effectively be executed. Multithreaded programs present many difficult challenges as, for example, multithreaded applications require careful design and coordination of resources among multiple threads.
Referring to FIG. 1A, consider an example of computer code that computes the cumulative sum of numbers passed to it by the calling thread. FIG. 1A shows the pseudo-code for a function cumulative_sum(value) that computes, prints, and returns the running total of the numbers passed to it by a calling thread. In a single threaded environment this function works as expected; thus:
cumulative_sum(1)prints 1cumulative_sum(1)prints 2cumulative_sum(1)prints 3and so on. Internally, this function keeps a static variable called running_total to keep track of the cumulative sum so far. The static variable, by definition, is shared between different invocations of the function.
Now, consider a multithreading environment, where two threads A and B concurrently invoke cumulative_sum( ). One possible execution scenario is shown in FIG. 1A. The diagram shows the program code line numbers, and sequence in which they are executed by the two threads. In this scenario, thread B executes a line of code right after thread A has executed it, thus interleaving the execution of the two threads: A: Line 1, B: Line 1, A: Line 2, B: Line 2, A: Line 3, B: Line 3, A: Line 4, B: Line 4, A: Line 5, B: Line 5. As a consequence, both threads clobber each other's execution by modifying the shared static variable running_total, such that both threads produce incorrect results.
The conventional way to prevent the two threads from “clobbering” (or adversely interfering with) each other is to protect access to the shared variable running_total, as shown in FIG. 1B. Referring to FIG. 1B, a lock is taken before modifying the value of the shared variable running_total, and unlocked after changing the shared variable. This guarantees that only one thread is modifying the shared variable at a time. However, as shown in FIG. 1B, this approach still does not guarantee that results of the two independent threads will not interfere with each other, since the running_total variable is still shared among the threads.
In view of the foregoing, an improved framework for executing multiple threads and sharing resources in a multithreaded programming environment would be highly useful.
A scenario where multithreading presents additional challenges includes implementing the middleware for a data distribution system. FIG. 14 depicts a data distribution middleware that decouples producers and consumers of Data in a domain. Data Distribution Service (DDS) is a formal standard from the Object Management Group (OMG) popular in embedded systems, especially in industrial automation, aerospace, and defense applications. DDS specifies an API designed for enabling real-time data distribution. It uses a publish-subscribe communication model, and supports both messaging and data-object centric data models.
DDS uses a publish-subscribe (P-S) communication model. The P-S communication model uses asynchronous message passing between concurrently operating subsystems. The publish-subscribe model connects anonymous information producers with information consumers. The overall distributed system is composed of processes, each running in a separate address space possibly on different computers. We will call each of these processes a “participant application”. A participant may be a producer or consumer of data, or both.
Data producers declare the topics on which they intend to publish data; data consumers subscribe to the topics of interest. When a data producer publishes some data on a topic, all the consumers subscribing to that topic receive it. The data producers and consumers remain anonymous, resulting in a loose coupling of sub-systems, which is well suited for data-centric distributed applications. DDS targets real-time systems; the API and Quality of Service (QoS) are chosen to balance predictable behavior and implementation efficiency/performance.
The DCPS model builds on the idea of a “global data space” of data-objects that any entity can access. Applications that need data from this space declare that they want to subscribe to the data, and applications that want to modify data in the space declare that they want to publish the data. A data-object in the space is uniquely identified by its keys and topic, and each topic must have a specific type. There may be several topics of a given type. A global data space is identified by its domain id, each subscription/publication must belong to the same domain to communicate.
The data distribution middleware handles the actual distribution of data on behalf of a user application. The distribution of the data is controlled by user settable Quality of Service (QoS).
In view of the foregoing, an improved framework for executing multiple threads and sharing resources in a multithreaded computing environment would be highly useful.